import time
from typing import Any, Tuple

import uiautomator2 as u2
from uiautomator2 import UiObject

from MyPackage.AIPattern import AIPattern
import MyPackage.Constant as C
from MyPackage.ThreadPool import MessageThreadPool


class AutoReply(object):
    def __init__(self, device_id: str, app: str) -> None:
        """
        初始化实例信息
        :param device_id: 设备唯一标识
        :param app: 启动程序名
        """
        self.__device = self.__connect_device(device_id)
        self.__app = app
        self.__package, self.__constant_pool = self.__initialize_constant_pool()
        self.__message_thread = MessageThreadPool(self.__app)

    @staticmethod
    def __connect_device(device_id: str) -> u2.Device:
        """
        建立设备连接
        :param device_id: 设备唯一标识
        :return: 设备连接对象
        """
        try:
            return u2.connect(device_id)
        except Exception as e:
            raise Exception(f'设备连接失败, 具体原因: {e}')

    def __initialize_constant_pool(self) -> Tuple[Any, Any]:
        """
        初始化实例所需常量池
        :return: 常量枚举类
        """
        enum1 = 'App2Package'
        enum2 = self.__app + 'Constant'
        try:
            app2package = getattr(C, enum1)
            app2constant = getattr(C, enum2)
            return app2package, app2constant
        except AttributeError as e:
            raise AttributeError(f'常量池初始化错误, 具体原因: {e}')

    def __start_app(self) -> None:
        """
        启动程序
        :return:
        """
        try:
            self.__device.app_start(self.__package[self.__app].value[0], self.__package[self.__app].value[1])
        except Exception as e:
            raise Exception(f'程序启动失败, 具体原因: {e}')

    def __stop_app(self) -> None:
        """
        关闭程序
        :return:
        """
        try:
            self.__device.app_stop(self.__package[self.__app].value[0])
        except Exception as e:
            raise Exception(f'程序关闭失败, 具体原因: {e}')

    def __determine_reply(self, begin_time: float, span_time: int) -> None:
        """
        反射调用对应程序回复逻辑方法
        :param begin_time: 程序自动回复时间戳
        :param span_time: 持续回复时间
        :return:
        """
        call_method = '_AutoReply__' + self.__app.lower() + '_auto_reply'
        if call_method in AutoReply.__dict__:
            method = getattr(self, call_method)
            if callable(method):
                method(begin_time, span_time)

    def __wechat_auto_reply(self, begin_time: float, span_time: int,
                            main_nav_read_msg1_resource_id='MainNavRedMsg1',
                            main_ui_red_msg_resource_id='MainUIRedMsg',
                            message_el_class_name='MessageEl',
                            text_box_resource_id='TextBox',
                            send_button_resource_id='SendBtn') -> None:
        """
        微信自动回复逻辑
        :param begin_time: 自动回复开始时间戳
        :param span_time: 持续回复时间
        :param main_nav_read_msg1_resource_id: 主页底部导航图标新消息提示标识
        :param main_ui_red_msg_resource_id: 主页微信导航窗口新消息提示标识
        :param message_el_class_name: 聊天窗口内文本框定位Id
        :param text_box_resource_id: 聊天窗口内文本框定位Id
        :param send_button_resource_id: 聊天窗口内发送信息按钮定位Id
        :return:
        """
        while time.time() - begin_time < span_time:
            if self.__check_main_nav_red_msg(main_nav_read_msg1_resource_id):
                self.__handle_unread_message(main_ui_red_msg_resource_id, message_el_class_name,
                                             text_box_resource_id, main_nav_read_msg1_resource_id,
                                             send_button_resource_id)

    # 待扩展
    def __other_app_reply(self):
        pass

    # 调测方法
    def __test(self):
        self.__stop_app()
        # self.__device.app_start('com.tencent.mm', '.ui.LauncherUI')
        # print(self.__device.app_current())
        # print(self.__device(className=self.__constant_pool['MessageEl'].value)[-1].info)

    @staticmethod
    def __ai_reply(wait_msg: str) -> str:
        """
        生成AI回复信息
        :param wait_msg: 待回复信息
        :return AI回复信息
        """
        return '[AI]回复: ' + AIPattern('reply').reply(wait_msg)

    def __check_main_nav_red_msg(self, main_nav_read_msg1_resource_id) -> bool:
        """
        检查主页微信导航是否有新信息提示红点
        :param main_nav_read_msg1_resource_id: 主页底部导航新消息提示标识
        :return: 检查结果
        """
        if self.__device(resourceId=self.__constant_pool[main_nav_read_msg1_resource_id].value).wait(timeout=2):
            el = self.__device(resourceId=self.__constant_pool[main_nav_read_msg1_resource_id].value)
            self.__main_nav_msg1_total = int(el.get_text())
            return True
        return False

    def __handle_unread_message(self, main_ui_red_msg_resource_id: str,
                                message_el_class_name: str,
                                text_box_resource_id: str,
                                main_nav_read_msg1_resource_id: str,
                                send_button_resource_id: str
                                ) -> None:
        """
        处理未读消息逻辑
        :param main_ui_red_msg_resource_id: 主页微信导航窗口新消息提示标识
        :param message_el_class_name: 监听信息文本框标识
        :param text_box_resource_id: 聊天窗口内文本框定位Id
        :param main_nav_read_msg1_resource_id: 主页底部导航图标新消息提示标识
        :param send_button_resource_id: 聊天窗口内发送信息按钮定位Id
        :return:
        """
        if self.__device(resourceId=self.__constant_pool[main_ui_red_msg_resource_id].value).wait(timeout=2):
            current_wait_read_els = self.__device(resourceId=self.__constant_pool[main_ui_red_msg_resource_id].value)
            for current_wait_read_el in current_wait_read_els:
                current_wait_read_msg_num = int(current_wait_read_el.get_text())
                self.__main_nav_msg1_total -= current_wait_read_msg_num
                self.__enter_chat_window(current_wait_read_el, message_el_class_name)
                self.__process_chat_window(text_box_resource_id, send_button_resource_id)
                self.__exit_chat_window(main_nav_read_msg1_resource_id)

    def __enter_chat_window(self, current_wait_read_el: UiObject, message_el_resource_class_name: str) -> None:
        """
        进入待处理信息聊天窗口并开启消息监听
        :param current_wait_read_el: 当前待处理信息聊天窗口入口
        :param message_el_resource_class_name: 监听信息文本框标识
        :return:
        """
        current_wait_read_el.click()
        self.__message_thread.start_running()
        self.__message_thread.start_message_listener(self.__device,
                                                     self.__constant_pool[message_el_resource_class_name].value)
        time.sleep(2)

    def __process_chat_window(self, text_box_resource_id: str, send_button_resource_id: str) -> None:
        """
        处理聊天窗口信息回复
        :param text_box_resource_id: 聊天窗口内文本框定位Id
        :param send_button_resource_id: 聊天窗口内发送信息按钮定位Id
        :return:
        """
        while True:
            wait_reply_msg = self.__message_thread.get_new_message()
            if wait_reply_msg:
                self.__input_text_by_resource_id(self.__constant_pool[text_box_resource_id].value,
                                                 send_button_resource_id, wait_reply_msg)
            if self.__message_thread.get_message_queue_size() == 0:
                self.__message_thread.stop_running()
                self.__device.press('back')
                print('停止')
                break

    def __exit_chat_window(self, main_nav_read_msg1_resource_id: str) -> None:
        """
        退出聊天窗口时待处理逻辑
        :param main_nav_read_msg1_resource_id: 主页底部导航新消息提示标识
        :return:
        """
        if self.__device(resourceId=self.__constant_pool[main_nav_read_msg1_resource_id].value).wait(timeout=2):
            current_el = self.__device(resourceId=self.__constant_pool[main_nav_read_msg1_resource_id].value).get_text()
            current_main_msg_nav_msg1_total = int(current_el)
            if current_main_msg_nav_msg1_total != self.__main_nav_msg1_total:
                """
                待处理 考虑滑屏置顶
                """
                pass
            else:
                self.__device.swipe(500, 1500, 500, 1000, 0.3)

    def __input_text_by_resource_id(self, text_box_resource_id: str, send_button_resource_id, wait_msg: str) -> None:
        """
        AI回复信息输入聊天界面文本框
        :param text_box_resource_id: 聊天窗口内文本框定位Id
        :param send_button_resource_id: 聊天窗口内发送信息按钮定位Id
        :param wait_msg: 待回复信息
        :return:
        """
        self.__device(resourceId=text_box_resource_id).click()
        self.__device.set_input_ime(True)
        self.__device.send_keys(self.__ai_reply(wait_msg))
        self.__click_send_button_by_resource_id(self.__constant_pool[send_button_resource_id].value)
        self.__device.set_input_ime(False)

    def __click_send_button_by_resource_id(self, send_button_resource_id: str) -> None:
        """
        单击发送信息按钮
        :param send_button_resource_id: 聊天窗口内发送信息按钮定位Id
        :return:
        """
        self.__device.press('back')
        self.__device(resourceId=send_button_resource_id).click()

    def run(self):
        self.__start_app()
        self.__determine_reply(time.time(), 60)
        self.__stop_app()


if __name__ == '__main__':
    app1 = AutoReply('10.11.246.185', 'WeChat')
    app1.run()
